{
 "cells": [
  {
   "cell_type": "raw",
   "id": "dee81e02",
   "metadata": {},
   "source": [
    "__str__"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "0f7a3033",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<__main__.Student object at 0x0000025C961677C0>\n"
     ]
    }
   ],
   "source": [
    "class Student(object):\n",
    "    def __init__(self, name):\n",
    "        self.name = name\n",
    "\n",
    "print(Student('Bob'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "f859fb26",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<__main__.Student at 0x25c961676a0>"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "class Student(object):\n",
    "    def __init__(self, name):\n",
    "        self.name = name\n",
    "    def __str__(self):\n",
    "        return 'Student object (name %s)' % self.name\n",
    "\n",
    "s = Student('Bob')\n",
    "s"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "c479b249",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Student object (name Bob)\n"
     ]
    }
   ],
   "source": [
    "print(s)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1c91d931",
   "metadata": {},
   "source": [
    "可以看出直接显示变量调用的不是__str__()，而是__repr__()，两者区别是__str__()返回用户看到的字符串，而repr返回程序开发者看到的字符串"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f450af26",
   "metadata": {},
   "source": [
    "可以再定义一个repr方法，解决上面这个问题"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "1e7a5132",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Student object (name Bob)"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "class Student(object):\n",
    "    def __init__(self, name):\n",
    "        self.name = name\n",
    "    def __str__(self):\n",
    "        return 'Student object (name %s)' % self.name\n",
    "    __repr__ = __str__\n",
    "\n",
    "s = Student('Bob')\n",
    "s"
   ]
  },
  {
   "cell_type": "raw",
   "id": "01d95bc2",
   "metadata": {},
   "source": [
    "__iter__"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "27945765",
   "metadata": {},
   "source": [
    "如果一个类想被用于for  in 循环，就必须实现一个iter()方法，该方法返回一个迭代对象，然后for循环会不断调用迭代对象的next方法拿到虚幻的下一个值\n",
    "直到遇到StopIteration错误退出循环。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "7690ca48",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "1\n",
      "2\n",
      "3\n",
      "5\n",
      "8\n",
      "13\n",
      "21\n",
      "34\n",
      "55\n",
      "89\n"
     ]
    }
   ],
   "source": [
    "class Fib(object):\n",
    "    def __init__(self):\n",
    "        self.a, self.b = 0, 1\n",
    "    def __iter__(self):\n",
    "        return self\n",
    "    def __next__(self):\n",
    "        self.a, self.b = self.b, self.a + self.b\n",
    "        if self.a > 100:\n",
    "            raise StopIteration()\n",
    "        return self.a\n",
    "\n",
    "for n in Fib():\n",
    "    print(n)"
   ]
  },
  {
   "cell_type": "raw",
   "id": "008430a1",
   "metadata": {},
   "source": [
    "__getitem__"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f6215ac1",
   "metadata": {},
   "source": [
    "要表现的想list那样按照下标去除元素，需要实现getitem()方法："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "cc7c18ac",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "class Fib(object):\n",
    "    def __getitem__(self, n):\n",
    "        a, b = 1, 1\n",
    "        for x in range(n):\n",
    "            a, b = b , a + b\n",
    "        return a\n",
    "f = Fib()\n",
    "f[0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "fbe7bc31",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "70330367711422815821835254877183549770181269836358732742604905087154537118196933579742249494562611733487750449241765991088186363265450223647106012053374121273867339111198139373125598767690091902245245323403501"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "f[1000]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2e2e7a31",
   "metadata": {},
   "source": [
    "通过上面的方法，我们自己定义的类变现得和Python自带的list，tuple，dict没有区别，完全归功于动态语言的\n",
    "“鸭子类型”，不需要强制继承某个接口。"
   ]
  },
  {
   "cell_type": "raw",
   "id": "63867683",
   "metadata": {},
   "source": [
    "__getattr__"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dc6bf432",
   "metadata": {},
   "source": [
    "当调用一个不存在的属性时，可以写一个getattr方法，动态返回一个属性，避免报错。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "17e8fe83",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Bob'"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "class Student(object):\n",
    "    def __init__(self):\n",
    "        self.name = 'Bob'\n",
    "    def __getattr__(self, attr):\n",
    "        if attr == 'score':\n",
    "            return 99\n",
    "s = Student()\n",
    "s.name"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "d1384ad2",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "99"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "s.score"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "7b0d5c5b",
   "metadata": {},
   "outputs": [],
   "source": [
    "s.age"
   ]
  },
  {
   "cell_type": "raw",
   "id": "3faeea73",
   "metadata": {},
   "source": [
    "__call__"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "838d2a83",
   "metadata": {},
   "source": [
    "一个对象实例可以又自己的属性和方法，当我们调用实例方法时，我们用instance.method()来调用。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "df53f3ac",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "My name is Michael.\n"
     ]
    }
   ],
   "source": [
    "class Student(object):\n",
    "    def __init__(self,name):\n",
    "        self.name = name\n",
    "    def __call__(self):\n",
    "        print('My name is %s.' % self.name)\n",
    "s = Student('Michael')\n",
    "s()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "30c02417",
   "metadata": {},
   "source": [
    "对实例进行直接调用好比对一个函数进行调用一样，所以你完全可以把对象看成函数，把函数看成对象。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c079e589",
   "metadata": {},
   "source": [
    "我们更多时候需要判断一个对象是否能被调用，能被调用的对象就是一个Callable对象。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "6e41b567",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "callable(Student('Bob'))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b6419049",
   "metadata": {},
   "source": [
    "### 小结"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1e1b82ce",
   "metadata": {},
   "source": [
    "Python的class定义允许许多定制方法，可以让我们非常方便的生成特定的类"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "facdd3f2",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
